home *** CD-ROM | disk | FTP | other *** search
-
- // Varieties of ASCII armour for binary data
-
- var maxLineLength = 64; // Maximum line length for armoured text
-
- /* Hexadecimal Armour
-
- A message is encoded in Hexadecimal armour by expressing its
- bytes as a hexadecimal string which is prefixed by a sentinel
- of "?HX?" and suffixed by "?H", then broken into lines no
- longer than maxLineLength. Armoured messages use lower case
- letters for digits with decimal values of 0 through 15, but
- either upper or lower case letters are accepted when decoding
- a message. The hexadecimal to byte array interconversion
- routines in aes.js do most of the heavy lifting here. */
-
- var hexSentinel = "?HX?", hexEndSentinel = "?H";
-
- // Encode byte array in hexadecimal armour
-
- function armour_hex(b) {
- var h = hexSentinel + byteArrayToHex(b) + hexEndSentinel;
- var t = "";
- while (h.length > maxLineLength) {
- //dump("h.length", h.length);
- t += h.substring(0, maxLineLength) + "\n";
- h = h.substring(maxLineLength, h.length);
- }
- //dump("h.final_length", h.length);
- t += h + "\n";
- return t;
- }
-
- /* Decode string in hexadecimal armour to byte array. If the
- string supplied contains a start and/or end sentinel,
- only characters within the sentinels will be decoded.
- Non-hexadecimal digits are silently ignored, which
- automatically handles line breaks. We might want to
- diagnose invalid characters as opposed to ignoring them. */
-
- function disarm_hex(s) {
- var hexDigits = "0123456789abcdefABCDEF";
- var hs = "", i;
-
- // Extract hexadecimal data between sentinels, if present
-
- if ((i = s.indexOf(hexSentinel)) >= 0) {
- s = s.substring(i + hexSentinel.length, s.length);
- }
- if ((i = s.indexOf(hexEndSentinel)) >= 0) {
- s = s.substring(0, i);
- }
-
- // Assemble string of valid hexadecimal digits
-
- for (i = 0; i < s.length; i++) {
- var c = s.charAt(i);
- if (hexDigits.indexOf(c) >= 0) {
- hs += c;
- }
- }
- //dump("hs", hs);
- return hexToByteArray(hs);
- }
-
- /* Codegroup Armour
-
- Codegroup armour encodes a byte string into a sequence of five
- letter code groups like spies used in the good old days. The
- first group of a message is always "ZZZZZ" and the last "YYYYY";
- the decoding process ignores any text outside these start and
- end sentinels. Bytes are encoded as two letters in the range
- "A" to "X", each encoding four bits of the byte. Encoding uses
- a pseudorandomly generated base letter and wraps around modulo
- 24 to spread encoded letters evenly through the alphabet. (This
- refinement is purely aesthetic; the base letter sequence is
- identical for all messages and adds no security. If the message
- does not fill an even number of five letter groups, the last
- group is padded to five letters with "Z" characters, which are
- ignored when decoding. */
-
- var acgcl, acgt, acgg;
-
- // Output next codegroup, flushing current line if it's full
-
- function armour_cg_outgroup() {
- if (acgcl.length > maxLineLength) {
- acgt += acgcl + "\n";
- acgcl = "";
- }
- if (acgcl.length > 0) {
- acgcl += " ";
- }
- acgcl += acgg;
- acgg = "";
- }
-
- /* Add a letter to the current codegroup, emitting it when
- it reaches five letters. */
-
- function armour_cg_outletter(l) {
- if (acgg.length >= 5) {
- armour_cg_outgroup();
- }
- acgg += l;
- }
-
- var codegroupSentinel = "ZZZZZ";
-
- function armour_codegroup(b) {
- var charBase = ("A").charCodeAt(0);
-
- acgcl = codegroupSentinel;
- acgt = "";
- acgg = "";
-
- var cgrng = new LEcuyer(0xbadf00d);
- for (i = 0; i < b.length; i++) {
- var r = cgrng.nextInt(23);
- armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] >> 4) & 0xF)) + r) % 24));
- r = cgrng.nextInt(23);
- armour_cg_outletter(String.fromCharCode(charBase + ((((b[i] & 0xF)) + r) % 24)));
- }
- delete cgrng;
-
- // Generate nulls to fill final codegroup if required
-
- while (acgg.length < 5) {
- armour_cg_outletter("Z");
- }
- armour_cg_outgroup();
-
- // Append terminator group
-
- acgg = "YYYYY";
- armour_cg_outgroup();
-
- // Flush last line
-
- acgt += acgcl + "\n";
-
- return acgt;
- }
-
- var dcgs, dcgi;
-
- /* Obtain next "significant" character from message. Characters
- other than letters are silently ignored; both lower and upper
- case letters are accepted. */
-
- function disarm_cg_insig() {
- while (dcgi < dcgs.length) {
- var c = dcgs.charAt(dcgi++).toUpperCase();
- if ((c >= "A") && (c <= "Z")) {
- //dump("c", c);
- return c;
- }
- }
- return "";
- }
-
- // Decode a message in codegroup armour
-
- function disarm_codegroup(s) {
- var b = new Array();
- var nz = 0, ba, bal = 0, c;
-
- dcgs = s;
- dcgi = 0;
-
- // Search for initial group of "ZZZZZ"
-
- while (nz < 5) {
- c = disarm_cg_insig();
-
- if (c == "Z") {
- nz++;
- } else if (c == "") {
- nz = 0;
- break;
- } else {
- nz = 0;
- }
- }
-
- if (nz == 0) {
- alert(strBundle.getFormattedString("armourCodegroupErrMessage", [ "Codegroup" ]));
- return "";
- }
-
- /* Decode letter pairs from successive groups
- and assemble into bytes. */
-
- var charBase = ("A").charCodeAt(0);
- var cgrng = new LEcuyer(0xbadf00d);
- for (nz = 0; nz < 2; ) {
- c = disarm_cg_insig();
- //dump("c", c);
-
- if ((c == "Y") || (c == "")) {
- break;
- } else if (c != "Z") {
- var r = cgrng.nextInt(23);
- var n = c.charCodeAt(0) - charBase;
- n = (n + (24 - r)) % 24;
- //dump("n", n);
- if (nz == 0) {
- ba = (n << 4);
- nz++;
- } else {
- ba |= n;
- b[bal++] = ba;
- nz = 0;
- }
- }
- }
- delete cgrng;
-
- /* Ponder how we escaped from the decoder loop and
- issue any requisite warnings. */
-
- var kbo = " " + strBundle.getString('armourCodegroupMessage');
- if (nz != 0) {
- alert(strBundle.getFormattedString("armourCodegroupErrMessage2", [ "Codegroup:" ]) + kbo);
- } else {
- if (c == "Y") {
- nz = 1;
- while (nz < 5) {
- c = disarm_cg_insig();
- if (c != "Y") {
- break;
- }
- nz++;
- }
- if (nz != 5) {
- alert(strBundle.getFormattedString("armourCodegroupErrMessage3", [ "Codegroup:" ]) + kbo);
- }
- } else {
- alert(strBundle.getFormattedString("armourCodegroupErrMessage4", [ "Codegroup:" ]) + kbo);
- }
- }
-
- return b;
- }
-
- /* Base64 Armour
-
- Base64 armour encodes a byte array as described in RFC 1341. Sequences
- of three bytes are encoded into groups of four characters from a set
- of 64 consisting of the upper and lower case letters, decimal digits,
- and the special characters "+" and "/". If the input is not a multiple
- of three characters, the end of the message is padded with one or two
- "=" characters to indicate its actual length. We prefix the armoured
- message with "?b64" and append "?64b" to the end; if one or both
- of these sentinels are present, text outside them is ignored. You can
- suppress the generation of sentinels in armour by setting base64addsent
- false before calling armour_base64. */
-
-
- var base64code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
- base64sent = "?b64", base64esent = "?64b", base64addsent = true;
-
- function armour_base64(b) {
- var b64t = "";
- var b64l = base64addsent ? base64sent : "";
-
- var i;
- for (i = 0; i <= b.length - 3; i += 3) {
- if ((b64l.length + 4) > maxLineLength) {
- b64t += b64l + "\n";
- b64l = "";
- }
- b64l += base64code.charAt(b[i] >> 2);
- b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
- b64l += base64code.charAt(((b[i + 1] & 0xF) << 2) | (b[i + 2] >> 6));
- b64l += base64code.charAt(b[i + 2] & 0x3F);
- }
-
- //dump("b.length", b.length); dump("i", i); dump("(b.length - i)", (b.length - i));
- if ((b.length - i) == 1) {
- b64l += base64code.charAt(b[i] >> 2);
- b64l += base64code.charAt(((b[i] & 3) << 4));
- b64l += "==";
- } else if ((b.length - i) == 2) {
- b64l += base64code.charAt(b[i] >> 2);
- b64l += base64code.charAt(((b[i] & 3) << 4) | (b[i + 1] >> 4));
- b64l += base64code.charAt(((b[i + 1] & 0xF) << 2));
- b64l += "=";
- }
-
- if ((b64l.length + 4) > maxLineLength) {
- b64t += b64l + "\n";
- b64l = "";
- }
- if (base64addsent) {
- b64l += base64esent;
- }
- b64t += b64l + "\n";
- return b64t;
- }
-
- function disarm_base64(s) {
- var b = new Array();
- var i = 0, j, c, shortgroup = 0, n = 0;
- var d = new Array();
-
- if ((j = s.indexOf(base64sent)) >= 0) {
- s = s.substring(j + base64sent.length, s.length);
- }
- if ((j = s.indexOf(base64esent)) >= 0) {
- s = s.substring(0, j);
- }
-
- /* Ignore any non-base64 characters before the encoded
- data stream and skip the type sentinel if present. */
-
- while (i < s.length) {
- if (base64code.indexOf(s.charAt(i)) != -1) {
- break;
- }
- i++;
- }
-
- /* Decode the base64 data stream. The decoder is
- terminated by the end of the input string or
- the occurrence of the explicit end sentinel. */
-
- while (i < s.length) {
- for (j = 0; j < 4; ) {
- if (i >= s.length) {
- if (j > 0) {
- alert(strBundle.getFormattedString("armourBase64ErrMessage", [ "Base64:" ]));
- return b;
- }
- break;
- }
- c = base64code.indexOf(s.charAt(i));
- if (c >= 0) {
- d[j++] = c;
- } else if (s.charAt(i) == "=") {
- d[j++] = 0;
- shortgroup++;
- } else if (s.substring(i, i + base64esent.length) == base64esent) {
- //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
- //dump("esent", i);
- i = s.length;
- continue;
- } else {
- //dump("s.substring(i, i + base64esent.length)", s.substring(i, i + base64esent.length));
- //dump("usent", i);
- // Might improve diagnosis of improper character in else clause here
- }
- i++;
- }
- //dump("d0", d[0]); dump("d1", d[1]); dump("d2", d[2]); dump("d3", d[3]);
- //dump("shortgroup", shortgroup);
- //dump("n", n);
- if (j == 4) {
- b[n++] = ((d[0] << 2) | (d[1] >> 4)) & 0xFF;
- if (shortgroup < 2) {
- b[n++] = ((d[1] << 4) | (d[2] >> 2)) & 0xFF;
- //dump("(d[1] << 4) | (d[2] >> 2)", (d[1] << 4) | (d[2] >> 2));
- if (shortgroup < 1) {
- b[n++] = ((d[2] << 6) | d[3]) & 0xFF;
- }
- }
- }
- }
- return b;
- }
-